from sqlalchemy import select, func
from utils.token_util import get_user_token, get_user_id_by_token
from utils.log_util import logger
from db.redis_part import xibie_redis
from db.mysql_part import get_mysql_session
from db.models import Pet
from app.config import (
    REDIS_USER_PREFIX, 
    REDIS_GAME_PREFIX, REDIS_GAME_EXPIRE
)
from app.exception.cus_exception import InvalidGameException
from app.handler.ws_manage import ws_manager, generate_event
from app.handler.delay_manage import delay_manager
from app.service.game_service import init_config_by_rule
import random
import string
import json
import asyncio


def check_token(token: str|None):
    if token is None:
        user_id = ''.join(random.choice(string.digits) for _ in range(4))
        while xibie_redis.exists(f'{REDIS_USER_PREFIX}{user_id}'):
            user_id = ''.join(random.choice(string.digits) for _ in range(4))
        token = get_user_token(user_id)
        return {'token': token, 'userid': user_id}
    else:
        user_id = get_user_id_by_token(token)
        return {'token': token, 'userid': user_id}

def get_user_nickname(token: str):
    user_id = get_user_id_by_token(token)
    return xibie_redis.hget(f'{REDIS_USER_PREFIX}{user_id}', 'nickname')

def set_user_nickname(token: str, nickname: str):
    user_id = get_user_id_by_token(token)
    xibie_redis.hset(f'{REDIS_USER_PREFIX}{user_id}', 'nickname', nickname)
    logger.debug(f"用户id：{user_id}，设置昵称：{nickname}")

def get_user_info(token: str):
    user_id = get_user_id_by_token(token)
    user_info = xibie_redis.hgetall(f'{REDIS_USER_PREFIX}{user_id}')
    user_info['userid'] = user_id
    del user_info['token']
    return user_info

def generate_game(token: str, options: dict):
    user_id = get_user_id_by_token(token)
    if xibie_redis.hget(f'{REDIS_USER_PREFIX}{user_id}', 'gameId') is not None:
        raise InvalidGameException('已在房间中', user_id)
    game_id = ''.join(random.choice(string.digits) for _ in range(6))
    while xibie_redis.exists(f'{REDIS_GAME_PREFIX}{game_id}'):
        game_id = ''.join(random.choice(string.digits) for _ in range(6))
    game_info = {
        'countTime': options['countTime'] if 'countTime' in options else 30,
        'groupId': options['groupId'],
        'player1RollCount': 2,
        'player2RollCount': 2,
        'player1HideCount': 3,
        'player2HideCount': 3,
        'wait': 1
    }

    if len(options['ruleList']) == 0:
        tmp = random.sample([i for i in range(1,7)], 2)
        tmp.sort()
        game_info['ruleFirst'] = f"rule{tmp[0]}"
        game_info['ruleSecond'] = f"rule{tmp[1]}"
    elif len(options['ruleList']) == 1:
        tmp = random.randint(1,6)
        game_info['ruleFirst'] = options['ruleList'][0]
        game_info['ruleSecond'] = f"rule{tmp}"
    elif len(options['ruleList']) == 2:
        game_info['ruleFirst'] = options['ruleList'][0]
        game_info['ruleSecond'] = options['ruleList'][1]

    game_info[options['side']] = user_id
    xibie_redis.hset(name=f'{REDIS_GAME_PREFIX}{game_id}', mapping=game_info)
    xibie_redis.expire(f'{REDIS_GAME_PREFIX}{game_id}', REDIS_GAME_EXPIRE)
    xibie_redis.hset(f'{REDIS_USER_PREFIX}{user_id}', 'gameId', game_id)
    init_config_by_rule(game_id, game_info['ruleFirst'])
    init_config_by_rule(game_id, game_info['ruleSecond'])
    logger.info(f"用户：{user_id}，创建对局：{game_id}")
    logger.info(f"对局：{game_id}，规则1：{game_info['ruleFirst']}，规则2：{game_info['ruleSecond']}")
    return game_id

async def join_game(token: str, options: dict):
    user_id = get_user_id_by_token(token)
    if xibie_redis.hget(f'{REDIS_USER_PREFIX}{user_id}', 'gameId') is not None:
        raise InvalidGameException('已在房间中', user_id)
    game_id = options['gameId']
    side = options['side']
    if not xibie_redis.exists(f'{REDIS_GAME_PREFIX}{game_id}'):
        raise InvalidGameException('房间不存在', user_id)
    game_info = xibie_redis.hgetall(f'{REDIS_GAME_PREFIX}{game_id}')
    if side in game_info and game_info[side]:
        raise InvalidGameException('该位置已被占用', user_id, game_id)
    if side == 'player1' or side == 'player2':
        xibie_redis.hset(f'{REDIS_GAME_PREFIX}{game_id}', side, user_id)
        await ws_manager.broadcast(game_id, generate_event('joinGame', {'userid': user_id, 'side': side}))
    xibie_redis.hset(f'{REDIS_USER_PREFIX}{user_id}', 'gameId', game_id)
    logger.debug(f"用户：{user_id}，加入对局：{game_id}")
    return True

def get_game_id(token: str):
    user_id = get_user_id_by_token(token)
    game_id = xibie_redis.hget(f'{REDIS_USER_PREFIX}{user_id}', 'gameId')
    if game_id is None:
        raise InvalidGameException('房间不存在', user_id)
    elif not xibie_redis.exists(f'{REDIS_GAME_PREFIX}{game_id}'):
        xibie_redis.hdel(f'{REDIS_USER_PREFIX}{user_id}', 'gameId')
        raise InvalidGameException('房间不存在', user_id)
    return game_id

async def search_pets(search_text: str, page_no: int=1, page_size: int=30):
    async with get_mysql_session() as session:
        stmt = select(Pet).where(Pet.pet_name.like(f'%{search_text}%') | Pet.pet_id.like(f'%{search_text}%'))
        count_stmt = select(func.count()).select_from(stmt.subquery())
        query_stmt = stmt.order_by(Pet.pet_origin_id.desc()).offset((page_no - 1) * page_size).limit(page_size)
        total = await session.execute(count_stmt)
        data = await session.execute(query_stmt)
        records = []
        for item in data.scalars().all():
            temp = item.to_dict()
            temp['pet_head'] = item.head_hs if item.head_hs else f"{item.pet_origin_id}.png"
            records.append(temp)
        return {
            'total': total.scalar(),
            'data': records
        }
